package tech.aichan.AiQA.config;

import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import tech.aichan.AiQA.filter.JwtAuthenticationTokenFilter;
import tech.aichan.AiQA.service.impl.UserDetails.UserDetailsServiceImpl;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import static org.springframework.security.config.Customizer.withDefaults;

/**
 * @author mengyu
 * @date 2024/03/03 10:31
 */
@Configuration
public class WebSecurityConfig {
    @Resource
    // JWT过滤器
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
    @Resource
    // 认证异常处理器 (AuthenticationException)
    private AuthenticationEntryPoint authenticationEntryPoint;
    @Resource
    // 权限异常处理器 (AccessDeniedException)
    private AccessDeniedHandler accessDeniedHandler;

    // TODO
//    @Resource
//    // 登录成功处理器
//    private AuthenticationSuccessHandler authenticationSuccessHandler;
//    @Resource
//    // 登录失败处理器
//    private AuthenticationFailureHandler authenticationFailureHandler;
//    @Resource
//    // 登出成功处理器
//    private LogoutSuccessHandler logoutSuccessHandler;


    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Bean
    public UserDetailsService userDetailsService(){
        return new UserDetailsServiceImpl();
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .csrf(AbstractHttpConfigurer::disable)
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .authorizeHttpRequests(auth -> auth
//                                .anyRequest().permitAll() // 放行所有请求
                        .requestMatchers(
                                "/user/login",
                                "/user/register",
                                "/user/forget",
                                "/mail/send",
                                "/user/hello"
                                ).permitAll()
                        .anyRequest().authenticated()
                )
                // 设置JWT过滤器
                .addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class)
                // 设置异常处理器 TODO
//                .exceptionHandling(handling -> handling
//                        .authenticationEntryPoint(authenticationEntryPoint)
//                        .accessDeniedHandler(accessDeniedHandler)
//                )
                // 跨域设置
                .cors(withDefaults());
        return http.build();
    }


    /**
     * 调用loadUserByUsername获得UserDetail信息，在AbstractUserDetailsAuthenticationProvider里执行用户状态检查
     *
     * @return
     */

    @Bean
    public AuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
        // DaoAuthenticationProvider 从自定义的 userDetailsService.loadUserByUsername 方法获取UserDetails
        authProvider.setUserDetailsService(userDetailsService());
        // 设置密码编辑器
        authProvider.setPasswordEncoder(passwordEncoder());
        return authProvider;
    }


    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
        return config.getAuthenticationManager();
    }
}
